#ifndef MX_DEPUI_COREPUI_HEADER
#   define MX_DEPUI_COREPUI_HEADER

#   include "detk/detk.h"
#   include "deds/deds.h"
#   include "depui/types.h"
#   include "depui/platform.h"
#   include <assert.h>

#   ifdef __cplusplus
extern "C" {
#   endif
	unsigned mx_start(void);
	int mx_execute(void);

/**events !Event types */
	typedef enum MX_EVENT {
		MX_NOTHING = 0,
		MX_DESTRUCT,
		MX_EXPOSE,
		MX_GEOMETRY,
		MX_DEFAULTRECT,
		MX_SELECT,
		MX_VSCROLL,
		MX_HSCROLL,
		MX_SCROLLAREA,
		MX_LIST_CHANGED,
		MX_THEME_CHANGE,
		MX_DIRTY,

		MX__INTERACT_BEGIN,
		MX_POINTER_ENTER,
		MX_POINTER_LEAVE,
		MX_POINTER_MOVE,
		MX_POINTER_PRESS,
		MX_POINTER_RELEASE,
		MX_POINTER_CLICK,
		MX_KEY,
		MX_KEY_UNUSED,
		MX__INTERACT_END,

		MX_FOCUS_GOT,
		MX_FOCUS_LOST,

		MX_GFXSEL_OK,
		MX_FILESEL_OK,
		MX_FONTSEL_OK,
		MX_THEMESEL_OK,

		MX_LAST
	} MX_EVENT;

	/* Event information known to all objects */
	typedef struct MX_EVENTSTACK {
		struct MX_OBJ *obj;
		MX_EVENT event;
		const void *data;
		unsigned int datalen;
		unsigned int _answer;
	} MX_EVENTSTACK;

	extern const MX_EVENTSTACK mx;

	unsigned int mx__event(struct MX_OBJ_DATA *obj, MX_EVENT type, const void *data, unsigned int datalen);

/**events !Send an event
This macro sends an event to an object. */
#   define mx_event(o,t,d,l) mx__event(MXOBJ(o),(t),(d),(l))

/**events !Check if two events match with type and destination
This macro is useful in window event handler to recognize events for
different objects. */
#   define mx_eventmatch(e,o) ((mx.event == (e)) && (MXOBJ(mx.obj)==MXOBJ(o)))

	void mx_answer(unsigned int answer);
	unsigned int mx_emit(MX_EVENT type, const void *data, unsigned int datalen);
	unsigned int mx_inform(MX_EVENT type, const void *data, unsigned int datalen);

	const MX_RECT *mx_expose_rect(void);
	unsigned mx_exposing(void);
	void mx__dirty(struct MX_OBJ_DATA *obj, const unsigned children);

/** !Mark an object for later redraw
This macro marks an object derived from MX_OBJ and optionally its
children as for later redraw. */
#   define mx_dirty(o,c) mx__dirty(MXOBJ(o),(c));

	void mx_expose_background(const MX_RECT * rect);
	void mx_theme_set(const MX_THEME * theme);

	typedef struct MX_GUIFONT {
		union {
			MX_ATOM atom;
		} base;
		MX_PLATFORM_FONT _font;
		unsigned allocated;
	} MX_GUIFONT;

	MX_GUIFONT *mx_guifont_load(const char *filename, const char *text);
	MX_GUIFONT *mx_guifont_index(int i);
	const char *mx_guifont_text(const MX_GUIFONT * guifont);

	void mx_guifont_default(MX_GUIFONT * guifont);

	typedef struct MX_POINTER_INFO {
		int x, y, b;
		int dx, dy;
	} MX_POINTER_INFO;

	const MX_POINTER_INFO *mx_pointer_info(void);
	unsigned mx_pointer_hold(void);
	unsigned mx_pointer_release(void);

	typedef struct MX_KEY_INFO {
		int code;
		int ascii;
	} MX_KEY_INFO;

	const MX_KEY_INFO *mx_key_info(void);

	typedef void (*MX_CLASS) (void);

	typedef struct MX_OBJ_DATA {
		union {
			MX_RECTATOM_DATA rectatom;
			MX_ATOM atom;
		} base;
		MX_CLASS _class;
		 MX_TREE(struct MX_OBJ_DATA);
		struct MX_WIN *_win;
		int _id;
#   ifdef MXDEBUG
		unsigned long _magic;
#   endif
		 MX_BITFIELD(_wantfocus);
		 MX_BITFIELD(_wantpointer);
		 MX_BITFIELD(_wantmove);
		 MX_BITFIELD(_destroying);
		 MX_BITFIELD(_selected);
		 MX_BITFIELD(_disabled);
	} MX_OBJ_DATA;

	typedef struct MX_OBJ {
		union {
			MX_OBJ_DATA obj;
			MX_RECTATOM_DATA rectatom;
			MX_ATOM atom;
		} base;
	} MX_OBJ;

/**type_conversion
!Convert to base MX_OBJ class */
#   define MXOBJ(o)   (&(o)->base.obj)

/** !Get an objects ID number
This macro returns the id number associated with an object. */
#   define MXID(o)    ((const int)(MXOBJ(o)->_id))

/**class !Return an objects class */
#   define MXCLASS(o) ((const MX_CLASS)(MXOBJ(o)->_class))

	int mx__x(const MX_OBJ_DATA * obj);
	int mx__y(const MX_OBJ_DATA * obj);

/** !Return the X-coordinate of an MX_OBJ */
#   define mx_x(o) mx__x(MXOBJ(o))

/** !Return the Y-coordinate of an MX_OBJ */
#   define mx_y(o) mx__y(MXOBJ(o))

	void mx__place(MX_OBJ_DATA * obj, const MX_RECT * rect);

/** !Place an MX_OBJ at a given recyangle */
#   define mx_place(o,r) mx__place(MXOBJ(o),(r))

	void mx__position(MX_OBJ_DATA * obj, int x, int y, int w, int h);

/** !Position an MX_OBJ at given coordinates */
#   define mx_position(o,x,y,w,h) mx__position(MXOBJ(o),(x),(y),(w),(h))

	void mx__move(MX_OBJ_DATA * obj, int x, int y);

/** !Move an MX_OBJ to a given poistion */
#   define mx_move(o,x,y) mx__move(MXOBJ(o),(x),(y))

	void mx__resize(MX_OBJ_DATA * obj, int w, int h);

/** !Resize an MX_OBJ to a given width and height */
#   define mx_resize(o,w,h) mx__resize(MXOBJ(o),(w),(h))

	void mx__geometry(MX_OBJ_DATA * obj);

/** !Make an object check/correct its geometry
This macro causes a MX_GEOMETRY event to be sent to an object.  The
object should do any internal processing necessary so the object functions properly
with the current poistion and size. */
#   define mx_geometry(o) mx__geometry(MXOBJ(o))

/** !Get default rect informatoin
When handling a MX_DEFAULTRECT event, and object can call this function to
get information as to where to put the default rect information. */
	MX_RECT *mx_defaultrect_data(void);

	void mx__defaultrect(MX_OBJ_DATA * obj, MX_RECT * rect);

/** !Find out what size/position and object wants to have
This macro causes a MX_DEFAULTRECT event to be sent to an object derived
from MX_OBJ. */
#   define mx_defaultrect(o,r) mx__defaultrect(MXOBJ(o),(r))

	typedef enum MX_LAYOUT {
		MX_LAYOUT_RIGHT = (1 << 0),
		MX_LAYOUT_LEFT = (1 << 1),
		MX_LAYOUT_TOP = (1 << 2),
		MX_LAYOUT_BOTTOM = (1 << 3),
		MX_LAYOUT_X1 = (1 << 4),
		MX_LAYOUT_Y1 = (1 << 5),
		MX_LAYOUT_X2 = (1 << 6),
		MX_LAYOUT_Y2 = (1 << 7),
		MX_LAYOUT_W = (1 << 8),
		MX_LAYOUT_H = (1 << 9),
		MX_LAYOUT_HCENTER = (1 << 10),
		MX_LAYOUT_VCENTER = (1 << 11),
		MX_LAYOUT_CENTER = MX_LAYOUT_HCENTER | MX_LAYOUT_VCENTER
	} MX_LAYOUT;

	void mx__layout(MX_OBJ_DATA * obj, MX_LAYOUT flags, const MX_OBJ_DATA * other, int x, int y);

/** !Set the layout of an MX_OBJ */
#   define mx_layout(o,f,r,x,y) mx__layout(MXOBJ(o),(f),MXOBJ(r),(x),(y))

	unsigned mx__armed(const MX_OBJ_DATA * obj);

/** !Return if an MX_OBJ is armed or not */
#   define mx_armed(o) mx__armed(MXOBJ(o))

	unsigned mx__selected(const MX_OBJ_DATA * obj);

/** !Return if an MX_OBJ is selected or not */
#   define mx_selected(o) mx__selected(MXOBJ(o))

	unsigned mx__select(MX_OBJ_DATA * obj, unsigned select);

/** !Select an MX_OBJ */
#   define mx_select(o,s) mx__select(MXOBJ(o),(s))

	void mx__disable(MX_OBJ_DATA * obj, unsigned disable);

/** !Disable an MXOBJ  */
#   define mx_disable(o,d) mx__disable(MXOBJ(o),(d))

	unsigned mx__disabled(const MX_OBJ_DATA * obj);

/** !Return if a MX_OBJ is disabled or not */
#   define mx_disabled(o) mx__disabled(MXOBJ(o))

	void mx__wantmove(MX_OBJ_DATA * obj, unsigned wantmove);

/** !Determine if an object recieves MX_POINTER_MOVE events */
#   define mx_wantmove(o,w) mx__wantmove(MXOBJ(o),(w))

	void mx__wantpointer(MX_OBJ_DATA * obj, unsigned wantpointer);

/** !Determine if an object will recieve MX_POINTER_* events */
#   define mx_wantpointer(o,w) mx__wantpointer(MXOBJ(o),(w))

	unsigned mx__haspointer(MX_OBJ_DATA * obj);

/** !Determine if an object has the pointer */
#   define mx_haspointer(o) mx__haspointer(MXOBJ(o))

	unsigned mx__wantfocus(MX_OBJ_DATA * obj, unsigned wantfocus);

/**focus !Determine if an object wants the focus or not
This function return non-zero if the focus was changed.  In this case the
object probaly needs to be marked as dirty. */
#   define mx_wantfocus(o,w) mx__wantfocus(MXOBJ(o),(w))

	unsigned mx__focused(const MX_OBJ_DATA * obj);

/**focus !Return if an MX_OBJ is focused or not */
#   define mx_focused(o) mx__focused(MXOBJ(o))

	unsigned mx__focus_default(MX_OBJ_DATA * obj);

/**focus !Set a object to be the default focus object
This function returns non-zero if the object immediatly received the focus
 i.e. no other object has the focus at that moment. */
#   define mx_focus_default(o) mx__focus_default(MXOBJ(o))

/**class !Class function for MX_OBJECT */
	void mx_obj_class(void);

	void *mx__obj(MX_OBJ_DATA * obj, MX_CLASS _class, size_t size, MX_OBJ_DATA * parent, int id);

/** !Construct an MX_OBJ object */
#   define mx_obj(o,c,s,p,i) mx__obj(MXOBJ(o),(c),(s),MXOBJ(p),(i))

	typedef enum MX_ALIGN {
		MX_ALIGN_NONE = 0,
		MX_ALIGN_RIGHT = (1 << 0),
		MX_ALIGN_LEFT = (1 << 1),
		MX_ALIGN_TOP = (1 << 2),
		MX_ALIGN_BOTTOM = (1 << 3),
		MX_ALIGN_HCENTER = (1 << 4),
		MX_ALIGN_VCENTER = (1 << 5),
		MX_ALIGN_CENTER = MX_ALIGN_HCENTER | MX_ALIGN_VCENTER
	} MX_ALIGN;

	typedef void (*MX__TEXTUAL_CHUNKER) (struct MX_TEXTUAL_DATA * textual);
	typedef void (*MX__TEXTUAL_SETTER) (struct MX_TEXTUAL_DATA * textual, const char *str, int len, MX_FREE dfree);
	typedef const char *(*MX__TEXTUAL_GETTER) (const struct MX_TEXTUAL_DATA * textual, int *len);

	typedef struct MX__TEXTCHUNK {
		MX_STRING text;
		int offset;
		MX_RECT rect;
		 MX_DLLIST_NODE(struct MX__TEXTCHUNK, struct MX_TEXTUAL_DATA);
		 MX_BITFIELD(normal);
		 MX_BITFIELD(cursor);
	} MX__TEXTCHUNK;

	typedef struct MX_TEXTUAL_DATA {
		union {
			MX_OBJ_DATA obj;
			MX_RECTATOM_DATA rectatom;
			MX_ATOM atom;
		} base;

		MX__TEXTUAL_SETTER _setter;
		MX__TEXTUAL_GETTER _getter;
		MX__TEXTUAL_CHUNKER _chunker;

		MX__TEXTCHUNK _first;
		 MX_DLLIST_ELEM(struct MX__TEXTCHUNK);

		MX_STRING _text;
		MX_ALIGN _align;
		 MX_REF(MX_GUIFONT) _font;

		int _textwidth;
		int _textheight;

		unsigned int _tabsize;
	} MX_TEXTUAL_DATA;

/**! A text object */
	typedef struct MX_TEXTUAL {
		union {
			MX_TEXTUAL_DATA textual;
			MX_OBJ_DATA obj;
			MX_RECTATOM_DATA rectatom;
			MX_ATOM atom;
		} base;
	} MX_TEXTUAL;

/**type_conversion
!Convert to MX_TEXTUAL base class */
#   define MXTEXTUAL(o)         (&(o)->base.textual)

	void mx__textual_set(MX_TEXTUAL_DATA * textual, const char *str, int len, MX_FREE dfree);

/** !Set the text of a MX_TEXTUAL object */
#   define mx_text_set(o,t,l,f) mx__textual_set(MXTEXTUAL(o),(t),(l),(f))

	void mx__textual_setcopy(MX_TEXTUAL_DATA * textual, const char *str, int len);

/** !Set the text of a MX_TEXTUAL object to a copy of some text */
#   define mx_text_setcopy(o,t,l) mx__textual_setcopy(MXTEXTUAL(o),(t),(l))

	void mx__textual_font(MX_TEXTUAL_DATA * textual, MX_GUIFONT * font);

/** !Set the font associated with the MX_TEXTUAL object */
#   define mx_text_font(o,f) mx__textual_font(MXTEXTUAL(o),(f))

	const char *mx__textual_text(const MX_TEXTUAL_DATA * textual, int *len);

/** !Return the text of a MX_TEXTUAL object */
#   define mx_text(o,l) mx__textual_text(MXTEXTUAL(o),(l))

	void mx__textual_align(MX_TEXTUAL_DATA * text, MX_ALIGN align);

/** !Set the alignment associated with the MX_TEXTUAL object */
#   define mx_text_align(o,a) mx__textual_align(MXTEXTUAL(o),(a))

	MX_ALIGN mx__textual_align_get(const MX_TEXTUAL_DATA * textual);

/** !Return the alignment associated with the MX_TEXTUAL object */
#   define mx_text_align_get(o) mx__textual_align_get(MXTEXTUAL(o))

/**class !Class function for MX_TEXTUAL */
	void mx_textual_class(void);

	MX_TEXTUAL *mx__textual(MX_TEXTUAL_DATA * textual, size_t size, MX_OBJ_DATA * parent, int id);

/** !Construct a MX_TEXTUAL object */
#   define mx_textual(m,s,p,i) mx__textual(MXTEXTUAL(m),(s),MXOBJ(p),(i))

	typedef struct MX_BUTTON_DATA {
		union {
			MX_TEXTUAL_DATA textual;
			MX_OBJ_DATA obj;
			MX_RECTATOM_DATA rectatom;
			MX_ATOM atom;
		} base;
	} MX_BUTTON_DATA;

	/* !Button object */
	typedef struct MX_BUTTON {
		union {
			MX_BUTTON_DATA button;
			MX_TEXTUAL_DATA textual;
			MX_OBJ_DATA obj;
			MX_RECTATOM_DATA rectatom;
			MX_ATOM atom;
		} base;
	} MX_BUTTON;

/**type_conversion
!Convert to MX_BUTTON base class */
#   define MXBUTTON(o)   (&(o)->base.button)

/**class !Class function for MX_BUTTON */
	void mx_button_class(void);

	MX_BUTTON *mx__button(MX_BUTTON_DATA * button, size_t size, MX_OBJ_DATA * parent, int id);

/** !Construct a button */
#   define mx_button(m,s,p,i) mx__button(MXBUTTON(m),(s),MXOBJ(p),(i))

/**events !Event handler
Functions of this type are assoctaied with windows.  These functions process
all events bieng passed to all objects within the window. */
	typedef void (*MX_HANDLER) (struct MX_WIN * win);

	typedef struct MX_WIN_DATA {
		union {
			MX_TEXTUAL_DATA textual;
			MX_OBJ_DATA obj;
			MX_RECTATOM_DATA rectatom;
			MX_ATOM atom;
		} base;
		MX_HANDLER _handler;

		MX_OBJ_DATA *_focus;
		MX_OBJ_DATA *_defaultfocus;

		struct MX_WINBORDER *border;

		 MX_TREE(struct MX_WIN_DATA);

		int _modallock;
		 MX_BITFIELD(_ismodal);
		 MX_BITFIELD(_notitle);
		 MX_BITFIELD(_nomove);
	} MX_WIN_DATA;

/** !A window object */
	typedef struct MX_WIN {
		union {
			MX_WIN_DATA win;
			MX_TEXTUAL_DATA textual;
			MX_OBJ_DATA obj;
			MX_RECTATOM_DATA rectatom;
			MX_ATOM atom;
		} base;
	} MX_WIN;

/**type_conversion
!Convert to base MX_WIN class
This macro does a typesafe conversion between an object derived from MX_WINDOW
and the underlying window. */
#   define MXWIN(o)   (&(o)->base.win)

/**class !Class function for MX_WIN */
	void mx_win_class(void);

/**events !The default window handler function */
	void mx_win_handler(MX_WIN * win);

/**events !The default window handler function */
	void mx_default_handler(void);

	MX_WIN *mx__win(MX_WIN_DATA * win, size_t size, MX_HANDLER handler, int id);

/** !Construct a standard window (and border) */
#   define mx_win(w,s,h,i) mx__win(MXWIN(w),(s),(h),(i))

	MX_WIN *mx__basicwin(MX_WIN_DATA * win, size_t size, MX_HANDLER handler, int id);

/** !Construct a basic window (no boprder) */
#   define mx_basicwin(w,s,h,i) mx__basicwin(MXWIN(w),(s),(h),(i))

	unsigned mx__active(const MX_WIN_DATA * win);

/** !Is window active?
This function returns non-zero if an object derivded from MX_WIN is the
active window.  This macro is just a wrapper for mx_win_active(). */
#   define mx_active(w) mx__active(MXWIN(w))

	void mx__win_dirty(MX_WIN_DATA * win);

/** !Mark a window for later redraw
This function marks a window and its border for redraw */
#   define mx_win_dirty(w) mx__win_dirty(MXWIN(w))

	void mx__win_modal(MX_WIN_DATA * win);

/** !Make a window modal
This macro marks a window as modal. This means that no interaction can take
place with a parent window while a child modal window is open.  */
#   define mx_modal(w) mx__win_modal(MXWIN(w))

	typedef struct MX_WINBORDER {
		union {
			MX_OBJ_DATA obj;
			MX_RECTATOM_DATA rectatom;
			MX_ATOM atom;
		} base;
		MX_HANDLER _callback;
		MX_BUTTON _close;
		MX_BUTTON _resize;
	} MX_WINBORDER;

/**class !Class function for MX_WINBORDER */
	void mx_winborder_class(void);

	void mx_winborder_callback(MX_WIN * win);

	MX_WINBORDER *mx__winborder(MX_WINBORDER * border, size_t size, MX_WIN_DATA * owner, int id);

/** !Create a border for a window */
#   define mx_winborder(b,s,o,i) mx__winborder((b),(s),MXWIN(o),(i))

	void mx__win_noresize(MX_WIN_DATA * win, unsigned res);

/** !Make a window resizeable/unresizable */
#   define mx_win_noresize(w,res) mx__win_noresize(MXWIN(w), (res))

	void mx__win_noclose(MX_WIN_DATA * win, unsigned res);

/** !Make a window closeable/uncloseable */
#   define mx_win_noclose(w,res) mx__win_noclose(MXWIN(w), (res))

	void mx__win_notitle(MX_WIN_DATA * win, unsigned res);

/** !Make a window moveable/unmoveable */
#   define mx_win_nomove(w,res) mx__win_nomove(MXWIN(w), (res))

	void mx__win_nomove(MX_WIN_DATA * win, unsigned res);

/** !Make a window have no title */
#   define mx_win_notitle(w,res) mx__win_notitle(MXWIN(w), (res))

	void mx__win_rootchild(MX_WIN_DATA * win);

/** !Make a window a child of the root window */
#   define mx_win_rootchild(w) mx__win_rootchild(MXWIN(w))

	/* For composite objects we can set an ID as a helper */
	typedef enum MX__ID {
		MXID_WINBORDER = 0xf000,
		MXID_WINCLOSE,
		MXID_WINRESIZE,
		MXID_SCROLLELEM,
		MXID_FONTSELLOAD
	} MX__ID;

	/* Internal functions */
	extern void mx__gui_redraw(const MX_RECT * rect);
	extern void mx___textual_chunker(MX_TEXTUAL_DATA * textual);
	extern void mx__textual_chunk(MX_TEXTUAL_DATA * textual);
	extern MX__TEXTCHUNK *mx__textchunk(MX_TEXTUAL_DATA * textual);
	extern void mx__textchunk_free(MX__TEXTCHUNK * chunk);
	extern void *mx__textual_platform_font(const MX_TEXTUAL_DATA * textual);

	extern const MX_THEME *mx__theme;
	extern struct MX_SYSMENU *mx__sysmenu;

	extern void mx__scroll_geometry(struct MX_SCROLL_DATA *scroll, int x1, int y1, int x2, int y2);

	extern void mx__event_default(void);

	extern void mx__popup(MX_WIN_DATA * win);
	extern void mx__puiexit(void);

/*--------------------------------------------------------------------------*/
	/* Some helper macros */
#   ifdef MXDEBUG
#      define MXMAGIC 0xbeefd00dl
#      define MXDEBUG_INVARIANT(o) do {   \
	assert(o);                      \
	assert((o)->_class);            \
	assert((o)->_win);              \
	assert((o)->_magic == MXMAGIC); \
} while(0)
#      define MXDEBUG_CLASSINVARIANT(o) do { \
    MXDEBUG_INVARIANT(o);           \
    if (mx.event == MX_DESTRUCT) {  \
        assert((o)->_destroying);   \
    } else if (mx__.exposing) {     \
        assert(mx.event == MX_EXPOSE); \
    } else {                        \
        assert(!(o)->_destroying);  \
        assert(mx_locked(o));       \
    }                               \
} while(0)
#   else
#      define MXDEBUG_INVARIANT(o) do {   \
} while(0)
#      define MXDEBUG_CLASSINVARIANT(o) do {   \
} while(0)
#   endif

#   define MXMINSIZE(s,a)                   \
    if ((s == MXDEFAULT) || (s < sizeof(a))) \
        s = sizeof(a);

/*--------------------------------------------------------------------------*/
#   ifdef __cplusplus
}
#   endif
#endif
